package org.hs.phd.odi.tracking.tracker.particlefilter.tracker;

import java.awt.Polygon;

import org.hs.phd.odi.tracking.tracker.Histogram;
import org.hs.phd.odi.tracking.tracker.TrackWindow;
import org.hs.phd.odi.tracking.tracker.Tracker;
import org.hs.phd.odi.tracking.tracker.histogram.Weighted3DHistogram;
import org.hs.phd.odi.tracking.tracker.kernel.EpanechnikovKernel;
import org.hs.phd.odi.tracking.tracker.particlefilter.core.Particle;
import org.hs.phd.odi.tracking.tracker.particlefilter.core.ParticleFilter;

import com.googlecode.javacv.cpp.opencv_core.IplImage;

public abstract class AbstractSingleObjectParticleFilterTracker<T> implements Tracker, ParticleStateTrackShapeConvertor<T> {

	private TrackWindow trackWindow;
	private boolean trackInitialized;
	
	private ParticleFilter<T> particleFilter;

	
	protected AbstractSingleObjectParticleFilterTracker(TrackWindow trackWindow){
		this.trackWindow = trackWindow;
		trackInitialized = false;
	}
	
	@Override
	public TrackWindow init(Polygon initialTrackShape, IplImage initialFrame) {
		trackInitialized = true;
		trackWindow.moveToBestMatchingLocationFor(initialTrackShape);
		Histogram targetHistogram = new Weighted3DHistogram(32,32,16, new EpanechnikovKernel());
		targetHistogram.calculateFrom(initialFrame, trackWindow);
		
		
		particleFilter = createParticleFilter(initialFrame, targetHistogram, trackWindow);
		
		Particle<T> initialParticle = createInitialParticle(trackWindow);
		
		particleFilter.initParticlesFromSingleParticle(initialParticle);
		
		return trackWindow;
	}


	protected abstract Particle<T> createInitialParticle(TrackWindow trackWindow) ;

	protected abstract ParticleFilter<T> createParticleFilter(IplImage initialFrame, Histogram targetHistogram, TrackWindow trackWindow);

	public abstract void updateTrackWindowUsingParticleState(TrackWindow trackWindow, T particleState);

	@Override
	public TrackWindow track(IplImage frame) {
		
		if(!trackInitialized) return null;
		
		particleFilter.computeNextGeneration(frame);
		Particle<T> mostLikelyParticle = particleFilter.getMostLikelyParticle();
		
		updateTrackWindowUsingParticleState(trackWindow, mostLikelyParticle.getCurrentState());
		
		return trackWindow;
	}

	@Override
	public TrackWindow getCurrentTrackWindow() {
		return trackWindow;
	}

}
